package dbx

import (
	"fmt"
	"gorm.io/driver/mysql"
	"gorm.io/driver/postgres"
	"gorm.io/gen"
	"gorm.io/gorm"
	"strings"
)

func InitMysql(config DataBase, opts ...func(*gorm.Config)) *gorm.DB {
	var uri = strings.Join([]string{config.Username, ":", config.Password,
		"@tcp(", config.Host, ")/", config.DataBase, "?charset=utf8mb4&parseTime=True&loc=Local"}, "")
	g := &gorm.Config{
		DisableForeignKeyConstraintWhenMigrating: true,
	}
	for _, v := range opts {
		v(g)
	}
	user, err := gorm.Open(mysql.Open(uri), g)
	if err != nil {
		panic(err)
	}
	return user
}
func GormGenConfig(outPath, modelPkgPath string, handlers ...func(g *gen.Generator)) *gen.Generator {
	generator := gen.NewGenerator(gen.Config{
		OutPath: outPath,
		//ModelPkgPath: modelPkgPath,
		WithUnitTest: false,

		// 表字段可为 null 值时, 对应结体字段使用指针类型
		FieldNullable: false, // generate pointer when field is nullable

		// 表字段默认值与模型结构体字段零值不一致的字段, 在插入数据时需要赋值该字段值为零值的, 结构体字段须是指针类型才能成功, 即`FieldCoverable:true`配置下生成的结构体字段.
		// 因为在插入时遇到字段为零值的会被GORM赋予默认值. 如字段`age`表默认值为10, 即使你显式设置为0最后也会被GORM设为10提交.
		// 如果该字段没有上面提到的插入时赋零值的特殊需要, 则字段为非指针类型使用起来会比较方便.
		FieldCoverable: false, // generate pointer when field has default value, to fix problem zero value cannot be assign: https://gorm.io/docs/create.html#Default-Values

		// 模型结构体字段的数字类型的符号表示是否与表字段的一致, `false`指示都用有符号类型
		FieldSignable: false, // detect integer field's unsigned type, adjust generated data type
		// 生成 gorm 标签的字段索引属性
		FieldWithIndexTag: false, // generate with gorm index tag
		// 生成 gorm 标签的字段类型属性
		FieldWithTypeTag: true, // generate with gorm column type tag

		Mode: gen.WithDefaultQuery,
	})

	// 自定义字段的数据类型
	// 统一数字类型为int64,兼容protobuf
	var dataMap = map[string]func(gorm.ColumnType) (dataType string){
		"tinyint":   func(detailType gorm.ColumnType) (dataType string) { return "int32" },
		"smallint":  func(detailType gorm.ColumnType) (dataType string) { return "int32" },
		"mediumint": func(detailType gorm.ColumnType) (dataType string) { return "int32" },
		"bigint":    func(detailType gorm.ColumnType) (dataType string) { return "int32" },
		"int":       func(detailType gorm.ColumnType) (dataType string) { return "int32" },
	}
	// 要先于`ApplyBasic`执行
	generator.WithDataTypeMap(dataMap)
	for _, v := range handlers {
		v(generator)
	}
	return generator
}
func InitPostgres(config DataBase, opts ...func(*gorm.Config)) *gorm.DB {
	split := strings.Split(config.Host, ":")
	if len(split) < 2 {
		panic("ip addr")
		return nil
	}
	port := split[len(split)-1]
	host := strings.TrimSuffix(config.Host, ":"+port)
	dsn := fmt.Sprintf("user=%s password=%s dbname=%s host=%s port=%s sslmode=disable TimeZone=Asia/Shanghai",
		config.Username, config.Password, config.DataBase, host, port)
	g := &gorm.Config{}
	for _, v := range opts {
		v(g)
	}
	db, err := gorm.Open(postgres.New(postgres.Config{
		DSN:                  dsn,
		PreferSimpleProtocol: true, // disables implicit prepared statement usage
	}), g)
	if err != nil {
		panic(err)
	}
	return db
}
